package pers.lonestar.framework.utils.support.write;

import java.lang.reflect.Field;
import java.util.List;

import pers.lonestar.framework.utils.support.annotations.ExcelSheetProperty;
import pers.lonestar.framework.utils.support.converters.Converter;
import pers.lonestar.framework.utils.support.metadata.write.WriteSheet;
import pers.lonestar.framework.utils.support.utils.FieldUtil;
import pers.lonestar.framework.utils.support.utils.StringUtil;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class ExcelWriterSheetBuilder {
    private final WriteSheet writeSheet;
    private ExcelWriter excelWriter;

    public ExcelWriterSheetBuilder() {
        this.writeSheet = new WriteSheet();
    }

    public ExcelWriterSheetBuilder(ExcelWriter excelWriter) {
        this.writeSheet = new WriteSheet();
        this.excelWriter = excelWriter;
    }

    public ExcelWriterSheetBuilder sheetIndex(Integer sheetIndex) {
        this.writeSheet.setSheetIndex(sheetIndex);
        return this;
    }

    public ExcelWriterSheetBuilder sheetName(String sheetName) {
        this.writeSheet.setSheetName(sheetName);
        return this;
    }

    public ExcelWriterSheetBuilder head(Class<?> headClass) {
        this.writeSheet.setHeadClass(headClass);
        this.writeSheet.setHasHead(true);
        return this;
    }

    public ExcelWriterSheetBuilder head(List<String> headList) {
        return head(headList, headList);
    }

    public ExcelWriterSheetBuilder head(List<String> headNameList, List<String> headTitleList) {
        this.writeSheet.setHeadNameList(headNameList);
        this.writeSheet.setHeadTitleList(headTitleList);
        this.writeSheet.setHasHead(true);
        return this;
    }

    public ExcelWriterSheetBuilder data(Flux<?> dataFlux) {
        if (dataFlux == null) {
            throw new IllegalArgumentException("DataFlux must not be null");
        }
        this.writeSheet.setDataFlux(dataFlux);
        return this;
    }

    public ExcelWriterSheetBuilder data(List<?> dataList) {
        if (dataList == null) {
            throw new IllegalArgumentException("DataList must not be null");
        }
        this.writeSheet.setDataFlux(Flux.fromIterable(dataList));
        return this;
    }

    public WriteSheet build() {
        if (this.writeSheet.getDataFlux() == null) {
            throw new IllegalArgumentException("DataFlux must not be null");
        }
        Class<?> headClass = writeSheet.getHeadClass();
        if (headClass != null) {
            //更新HeadClass相关参数
            List<Field> fieldList = FieldUtil.getSortedDeclaredFieldList(headClass);
            List<String> headNameList = FieldUtil.getSortedDeclaredFieldNameList(fieldList);
            List<? extends Converter> converterList = FieldUtil.getSortedDeclaredFieldConverterList(fieldList);
            writeSheet.setFieldList(fieldList);
            writeSheet.setHeadNameList(headNameList);
            writeSheet.setConverterList(converterList);

            ExcelSheetProperty sheetProperty = headClass.getAnnotation(ExcelSheetProperty.class);
            if (sheetProperty == null) {
                if (StringUtil.isEmpty(writeSheet.getSheetName())) {
                    writeSheet.setSheetName(headClass.getSimpleName());
                }
            } else {
                if (writeSheet.getSheetIndex() == null) {
                    writeSheet.setSheetIndex(sheetProperty.index());
                }
                if (StringUtil.isEmpty(writeSheet.getSheetName())) {
                    writeSheet.setSheetName(sheetProperty.name());
                }
            }
        }
        return writeSheet;
    }

    public Mono<Void> doWrite(List<?> dataList) {
        if (dataList == null) {
            throw new IllegalArgumentException("DataList must not be null");
        }
        return doWrite(Flux.fromIterable(dataList));
    }

    public Mono<Void> doWrite(Flux<?> dataFlux) {
        if (dataFlux == null) {
            throw new IllegalArgumentException("DataFlux must not be null");
        }
        writeSheet.setDataFlux(dataFlux);
        return excelWriter.write(build());
    }
}
